/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.seari.ibpPanleMidware.main;

import com.ghgande.j2mod.modbus.io.ModbusTCPTransaction;
import com.ghgande.j2mod.modbus.msg.WriteSingleRegisterRequest;
import com.ghgande.j2mod.modbus.net.TCPMasterConnection;
import com.seari.commonutils.redis.JedisPoolUtil;
import com.seari.commonutils.redis.JedisUtilProxy;
import com.seari.ibpPanleMidware.bean.StationConfig;
import com.seari.ibpPanleMidware.utils.UnityRegister;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;

/**
 *
 * @author Rainbow
 */
@Component
public class IbpCommandProcessor implements Runnable
{
    protected static Logger logger = LoggerFactory.getLogger(IbpCommandProcessor.class);
    public HashMap<String, Integer> valueCacheMap = new HashMap<>(40); //初始容量30，需要缓存的数据大约为30条
    public boolean terminate = false;
    public static String key;
    public List<StationConfig> stationConfigs;
    Jedis jedis = null;
    @Override
    public void run()
    {
        try
        {
            if(null != stationConfigs && stationConfigs.size() > 0)
            {
                jedis = JedisUtilProxy.getJedis();
                Pipeline pipeline = jedis.pipelined();
                key = stationConfigs.get(0).getCommandTableName();
                while (!terminate)
                {                    
                    if(jedis.isConnected())
                    {
                        for (StationConfig stationConfig : stationConfigs)
                        {
                            pipeline.hget(key, stationConfig.getStationId()+ "");
                        }
                        List<Object> results = pipeline.syncAndReturnAll();
                        processCommand(results);
                    }else{
                        //JEDIS连接失败时将当前连接回收至连接池，并获取新连接
                        JedisUtilProxy.close(jedis);
                        JedisUtilProxy.getJedisPool().returnBrokenResource(jedis);
                        jedis = JedisUtilProxy.getJedis();
                    }
                    TimeUnit.SECONDS.sleep(1);
                }
            }
            else
            {
                System.out.println("station configs is null ,terminate IbpCommandProcessor thread");
                terminate = true;
            }
        } catch (Exception e)
        {
            e.printStackTrace();
        }
        finally{
            JedisUtilProxy.close(jedis);
            //终止标志不为真时，认为此线程非正常退出，进行线程重启
            if(!terminate)
            {
                    try
                    {
                        TimeUnit.SECONDS.sleep(2);
                        Thread.currentThread().interrupt();
                    } catch (Exception e2)
                    {
                        // TODO: handle exception
                    }
                    new Thread(this).start();
            }
        }
    }
    private void processCommand(List<Object> results)
    {
        if(null == results || results.size() < 1)
        {
            return;
        }
        for(int i = 0; i < results.size(); i++)
        {
            String result = (String)results.get(i); 
            //默认当前值为0
            int currentValue = 0;
            if(StringUtils.isNotBlank(result)) //结果不为空
            {
                currentValue = Integer.parseInt(result);
            }
            StationConfig stationConfig = stationConfigs.get(i);
            if(valueCacheMap.containsKey(key + stationConfig.getStationId()))
            {
                //缓存MAP存在此键时，判断当前值与上次值是否相同，不同则放入缓存MAP并判断是否为需要处理的指令
                int lastValue = valueCacheMap.get(key + stationConfig.getStationId());
                if(lastValue != currentValue)
                {
                    valueCacheMap.put(key + stationConfig.getStationId(), currentValue);
                    if(0 != currentValue)
                    {
                        sendCommand(stationConfig,currentValue);
                    }
                }
            }else {
                //缓存MAP中不存在此键时，放入缓存MAP并判断是否为需要处理的指令
                valueCacheMap.put(key + stationConfig.getStationId(), currentValue);
                if(0 != currentValue)
                {
                    sendCommand(stationConfig,currentValue);
                }
            }
        }
    }
    
    private void sendCommand(StationConfig stationConfig,int currentValue)
    {
        boolean result = writeRegister(stationConfig, currentValue);
        if(result)
        {
            //指令下发成功置0
            jedis.hset(stationConfig.getCommandTableName(), stationConfig.getStationId()+"", 0+"");
        }else{
            //指令下发失败置-1
            jedis.hset(stationConfig.getCommandTableName(), stationConfig.getStationId()+"", -1+"");
        }
    }
    
    //激活模式
    private boolean processExtendCommand(StationConfig stationConfig,TCPMasterConnection connection)throws Exception
    {
        boolean flag = false;
        ModbusTCPTransaction trans = new ModbusTCPTransaction(connection);
        UnityRegister register = new UnityRegister(1);
        WriteSingleRegisterRequest req = new WriteSingleRegisterRequest(Integer.parseInt(stationConfig.getCommandExtend1()), register);
        req.setUnitID(1);
        trans.setRetries(2);
        trans.setRequest(req);
        logger.info("ModbusSlave: FC" + req.getFunctionCode()
                        + " ref=" + req.getReference() + " value="
                        + register.getValue());
        trans.execute();
        flag = true;
        return flag;
    }
    
    //清除火灾
    private boolean processExtendCommand2(StationConfig stationConfig,TCPMasterConnection connection)throws Exception
    {
        boolean flag = false;
        ModbusTCPTransaction trans = new ModbusTCPTransaction(connection);
        UnityRegister register = new UnityRegister(1);
        WriteSingleRegisterRequest req = new WriteSingleRegisterRequest(Integer.parseInt(stationConfig.getCommandExtend2()), register);
        req.setUnitID(1);
        trans.setRetries(2);
        trans.setRequest(req);
        logger.info("ModbusSlave: FC" + req.getFunctionCode()
                        + " ref=" + req.getReference() + " value="
                        + register.getValue());
        trans.execute();
        flag = true;
        return flag;
    }
    
    public boolean writeRegister(StationConfig stationConfig,int currentValue) 
    {
        boolean flag = false;
        TCPMasterConnection connection = null;
        String ipStrs[] = stationConfig.getCommandIpListArray();
        for (String ipStr : ipStrs)
        {
            try {
                InetAddress addr = InetAddress.getByName(ipStr);
                /*TCPMasterConnection */connection = new TCPMasterConnection(addr);
                connection.setPort(502);
                connection.setTimeout(200);
                connection.connect();
                if(4124 == currentValue)
                {
                    processExtendCommand2(stationConfig, connection);
                }
                ModbusTCPTransaction trans = new ModbusTCPTransaction(connection);
                UnityRegister register = new UnityRegister(currentValue);
                WriteSingleRegisterRequest req = new WriteSingleRegisterRequest(stationConfig.getCommandAddress(), register);
                req.setUnitID(1);
                trans.setRetries(2);
                trans.setRequest(req);
                logger.info("ModbusSlave: FC" + req.getFunctionCode()
                                + " ref=" + req.getReference() + " value="
                                + register.getValue());
                trans.execute();
                processExtendCommand(stationConfig, connection);
                flag = true;
                break;
            } catch (Exception ex) {
                System.out.println("Error in code");
                ex.printStackTrace();
            }finally{
                if(connection!=null)
                {
                    connection.close();
                }
            }
        }
        return flag;
    }
}
